package com.example.report.util;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.Map;

public class HttpClientUtil2 {
    private final static Logger log = LoggerFactory.getLogger(HttpClientUtil2.class);
    private final static String CHARSET_GBK = "gbk";
    private final static String CHARSET_UTF = "utf-8";
    private final static int defaultTimeout = 90000;
    public final static ThreadLocal<String> userInfo = new ThreadLocal<>();

    final static HttpConnectionManager httpConnectionManager = new MultiThreadedHttpConnectionManager();

    static {
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        params.setMaxTotalConnections(500);
        params.setDefaultMaxConnectionsPerHost(20);
        params.setConnectionTimeout(1000 * 10);
        params.setSoTimeout(defaultTimeout);
        httpConnectionManager.setParams(params);

    }

    public static String getConnectionsInPool() {
        MultiThreadedHttpConnectionManager manager = null;
        try {
            manager = MultiThreadedHttpConnectionManager.class.cast(httpConnectionManager);
            Class<?> obj = manager.getClass();
            Field f1 = obj.getDeclaredField("connectionPool");
            f1.setAccessible(true);

            Class[] cls = obj.getDeclaredClasses();
            Map m = null;
            for (Class c : cls) {
                if (c.getSimpleName().equals("ConnectionPool")) {
                    Object a1 = c.getDeclaredFields();
                    Field f2 = c.getDeclaredField("mapHosts");
                    f2.setAccessible(true);
                    Map map = Map.class.cast(f2.get(f1.get(manager)));
                    m = map;
                    break;
                }
            }
            if (null != m) {
                for (Class c : cls) {
                    if (c.getSimpleName().equals("HostConnectionPool")) {
                        StringBuilder sb = new StringBuilder();

                        Field f3 = c.getDeclaredField("numConnections");
                        f3.setAccessible(true);
                        for (Object host : m.keySet()) {
                            Object numConnections = f3.get(m.get(host));
                            sb.append(host);
                            sb.append(":");
                            sb.append(numConnections);
                            sb.append("|");
                        }
                        return sb.toString();
                    }
                }
            }

        } catch (Exception ex) {
        }
        if (null == manager) {
            return "noop";
        } else {
            return "" + manager.getConnectionsInPool();
        }
    }

    public static String executeGetRequestUTF(String url, Map<String, String> keyValueMap, int timeout) {
        return executeHttpRequestByGetType(url, keyValueMap, CHARSET_UTF, timeout);
    }

    public static String executeGetRequestGBK(String url, Map<String, String> keyValueMap, int timeout) {
        return executeHttpRequestByGetType(url, keyValueMap, CHARSET_GBK, timeout);
    }

    public static InputStream requestGetStreamUTF(String url, Map<String, String> keyValueMap, int timeout) {
        return executeHttpRequestStream(url, keyValueMap, CHARSET_UTF, timeout);
    }

    public static InputStream requestGetStreamGBK(String url, Map<String, String> keyValueMap, int timeout) {
        return executeHttpRequestStream(url, keyValueMap, CHARSET_GBK, timeout);
    }

    public static String executeGetRequestUTF(String url, Map<String, String> keyValueMap) {
        return executeHttpRequestByGetType(url, keyValueMap, CHARSET_UTF, defaultTimeout);
    }

    public static String executeGetRequestGBK(String url, Map<String, String> keyValueMap) {
        return executeHttpRequestByGetType(url, keyValueMap, CHARSET_GBK, defaultTimeout);
    }

    public static InputStream requestGetStreamUTF(String url, Map<String, String> keyValueMap) {
        return executeHttpRequestStream(url, keyValueMap, CHARSET_UTF, defaultTimeout);
    }

    public static InputStream requestGetStreamGBK(String url, Map<String, String> keyValueMap) {
        return executeHttpRequestStream(url, keyValueMap, CHARSET_GBK, defaultTimeout);
    }

    public static InputStream executeHttpRequestStream(String url, Map<String, String> keyValueMap, String charset, int timeout) {
        HttpClient client = new HttpClient(httpConnectionManager);
        StringBuffer sb = new StringBuffer(url);
        GetMethod getMethod = null;
        try {
            //设置请求参数
            if (keyValueMap != null) {
                Iterator it = keyValueMap.entrySet().iterator();
                if (keyValueMap.size() > 0) {
                    sb.append("?");
                    while (it.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
                        sb.append(entry.getKey() + "=" + entry.getValue() + "&");
                    }
                    sb.deleteCharAt(sb.length() - 1);
                }

            }
            getMethod = new GetMethod(sb.toString());
            log.info("query uri ===============" + getMethod.getURI());
            getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            getMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);
            //todo:设置超时时间
            getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, timeout);
            int statusCode = client.executeMethod(getMethod);
            if (statusCode != HttpStatus.SC_OK) {
                log.info("request '" + url + "' failed,the status is not 200,status:" + statusCode);
                return null;
            }
            InputStream responseBody = getMethod.getResponseBodyAsStream();
            return responseBody;
        } catch (Exception e) {
            log.error("executeHttpRequestByGetType发生异常！请检查网络和参数,url:" + url, e);
        }
        return null;
    }

    /**
     * get方式提交
     *
     * @param url
     * @param keyValueMap
     * @return
     */
    public static String executeHttpRequestByGetType(String url, Map<String, String> keyValueMap, String charset, int timeout) {
        HttpClient client = new HttpClient(httpConnectionManager);
        StringBuffer sb = new StringBuffer(url);
        GetMethod getMethod = null;
        try {
            //设置请求参数
            if (keyValueMap != null) {
                Iterator it = keyValueMap.entrySet().iterator();
                if (keyValueMap.size() > 0) {
                    sb.append("?");
                    while (it.hasNext()) {
                        Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
                        sb.append(entry.getKey() + "=" + entry.getValue() + "&");
                    }
                    sb.deleteCharAt(sb.length() - 1);
                }

            }
            getMethod = new GetMethod(sb.toString());
            log.info("query uri ===============" + getMethod.getURI());
            getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            getMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);
            //todo:设置超时时间
            getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, timeout);
            int statusCode = client.executeMethod(getMethod);
            if (statusCode != HttpStatus.SC_OK) {
                log.info("request '" + url + "' failed,the status is not 200,status:" + statusCode);
                return "";
            }
            InputStream inputStream = getMethod.getResponseBodyAsStream();
            return getStringByStream(inputStream, charset);
        } catch (Exception e) {
            log.error("executeHttpRequestByGetType发生异常！请检查网络和参数,url:" + url, e);
        } finally {
            if (getMethod != null) {
                getMethod.releaseConnection();
            }
            client.getHttpConnectionManager().closeIdleConnections(0);
        }
        return null;
    }

    public static String executeHttpRequestGBK(String url, Map<String, String> keyValueMap) {
        return executeHttpRequest(url, keyValueMap, CHARSET_GBK, defaultTimeout);
    }

    public static String executeHttpRequestUTF(String url, Map<String, String> keyValueMap) {
        return executeHttpRequest(url, keyValueMap, CHARSET_UTF, defaultTimeout);
    }

    /***
     *
     * @param url  请求url
     * @param keyValueMap  提交参数
     * @param charSet  字符编码
     * @param timeout  请求响应时间
     * @return
     */
    public static String executeHttpRequest(String url, Map<String, String> keyValueMap, String charSet, int timeout) {

        HttpClient client = new HttpClient(httpConnectionManager);
        //设置请求参数
        PostMethod postMethod = new PostMethod(url);
        postMethod.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
        postMethod.setRequestHeader("Cookie", "userInfo=" + userInfo.get());
        if (keyValueMap != null) {
            NameValuePair[] parameters = new NameValuePair[keyValueMap.size()];
            Iterator it = keyValueMap.entrySet().iterator();
            int c = 0;
            while (it.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
                NameValuePair nvp = new NameValuePair();
                nvp.setName(entry.getKey());
                nvp.setValue(entry.getValue());
                parameters[c] = nvp;
                c++;
            }
            postMethod.addParameters(parameters);
        }
        try {
            log.debug("query uri ===============" + postMethod.getURI());
            postMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
            postMethod.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charSet);
            //todo:设置超时时间
            postMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, timeout);
            int statusCode = client.executeMethod(postMethod);
            if (statusCode != HttpStatus.SC_OK) {
                log.info("request '" + url + "' failed,the status is not 200,status:" + statusCode);
                return "";
            }
            InputStream inputStream = postMethod.getResponseBodyAsStream();
            return getStringByStream(inputStream, charSet);
        } catch (Exception e) {
            log.error("executeHttpRequestString发生异常！请检查网络和参数url:" + url, e);
        } finally {
            postMethod.releaseConnection();
            client.getHttpConnectionManager().closeIdleConnections(0);
        }
        return null;
    }

    /****
     * 根据输入流 转换成 字符串
     * @param inputStream  输入流
     * @param charSet  字符编码
     * @return
     * @throws IOException
     */
    private static String getStringByStream(InputStream inputStream, String charSet) throws IOException {
        String str = "";
        if (inputStream != null) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream(4 * 1024);
            byte[] buffer = new byte[4096];
            int len;
            while ((len = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
            outputStream.close();
            byte[] responseBody = outputStream.toByteArray();
            if (responseBody != null) {
                str = new String(responseBody, 0, responseBody.length, charSet);
            }
        }
        return str;
    }
}
